package com.csm.dao;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;


public class BaseDaoCSM<T> {
	private String driverClass="oracle.jdbc.driver.OracleDriver";
	private String url="jdbc:oracle:thin:@localhost:1521:orcl";
	private String username="scott";
	private String password="123456";
	public Connection getConnection(){
		try {
			Class.forName(driverClass);//将驱动加载到内存
			return DriverManager.getConnection(url,username,password);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	public int executeUpdate(String sql,Object... paramsObjs){
		Connection conn = this.getConnection();
		PreparedStatement pra=null;
		try {
			pra=conn.prepareStatement(sql);
			if(paramsObjs!=null && paramsObjs.length>0){
				for(int i=0;i<paramsObjs.length;i++){
					pra.setObject(i+1, paramsObjs[i]);
				}
			}
			return pra.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}
	public void closeAll(ResultSet rs,Statement sta,Connection conn){
		try{
		if(rs!=null)rs.close();
		if(sta!=null)sta.close();
		if(conn!=null)conn.close();
		}catch(Exception e){
		e.printStackTrace();	
		}
	}
		public List<T> executeQuery3(String sql,Map<String, String> columnsMap,Class outputClass,Object... paramsObjs){
			List<T> list=new ArrayList<T>();//返回的结果集合
			//1、获得连接对象
			Connection conn=this.getConnection();
			PreparedStatement pra=null;
			ResultSet rs=null;
			try {
				//2、获得预编译语句集
				pra=conn.prepareStatement(sql);
				
				//2.1、设置占位符的值
				if(paramsObjs!=null && paramsObjs.length>0){
					for(int i=0;i<paramsObjs.length;i++){
						pra.setObject(i+1, paramsObjs[i]);
					}
				}
				
				//3、获得结果集并遍历
				rs=pra.executeQuery();
				while(rs.next()){
					list.add(this.getEntity2(rs,columnsMap,outputClass));//通过调用子类的重写方法获得泛形类的实例
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally{
				this.closeAll(rs, pra, conn);
			}
			return list;
		}
		public T getEntity2(ResultSet rs,Map<String, String> columnsMap,Class outputClass){
			T resultObj=null;
			try {
				//1、获得返回的泛型类的实例对象
				resultObj=(T) outputClass.newInstance();//注意泛型类必须提供无参构造
				
				//2、取值设置到结果实例中
				ResultSetMetaData rsd= rs.getMetaData();//用于获得返回的结果的列名和总数
				// rsd.getColumnCount()：返回列的总数
				if(rsd!=null && rsd.getColumnCount()>0){
					for(int i=0;i<rsd.getColumnCount();i++){
						String columnName=rsd.getColumnName(i+1);//列名
						
						Field field=null;
						String propertyName=columnName.toLowerCase();//转成全小写
						//1、按照列名和属性名一致（全小写）
						try {
							field=outputClass.getDeclaredField(propertyName);
						} catch (Exception e) {}
						//2、按照骆峰规则
						if(field==null){
							StringBuffer propertyNameBf=new StringBuffer();
							//按骆峰规则拼接属性名
							String[] attrs=propertyName.split("_");
							if(attrs!=null && attrs.length>0){
								for(String str:attrs){
									if(propertyNameBf.length()>0){
										// menu_id==>str=id==>Id
										propertyNameBf.append(str.substring(0, 1).toUpperCase()+str.substring(1));
									}else{
										// menu_id==>str=menu
										propertyNameBf.append(str);
									}
								}
							}
							propertyName=propertyNameBf.toString();
							try {
								field=outputClass.getDeclaredField(propertyName);
							} catch (Exception e) {}
						}
						//3、如果列名与属性名通过上面二种情况还是获取不到时，就取传参设置的值
						if(field==null && columnsMap!=null){
							try {
								propertyName=columnsMap.get(columnName.toLowerCase());
								field=outputClass.getDeclaredField(propertyName);
							} catch (Exception e) {}
						}
						
						//找到了要到的泛型实例的属性
						if(field!=null){
							String fieldName=field.getName();
							//通过setXxx()方法将值设置到属性中去
//							String methodName="set"+fieldName.substring(0, 1)+fieldName.substring(1);
//							Method method=outputClass.getDeclaredMethod(methodName, field.getType());
//							if(method!=null){
//								method.invoke(resultObj, rs.getObject(columnName));//会有类型转换的错误。
//							}
							Object value=rs.getObject(columnName);
							if(value!=null){
								BeanUtils.copyProperty(resultObj, fieldName, value);
							}
							
						}
					}
				}
				
			} catch (Exception e) {
				e.printStackTrace();
			}
			return resultObj;
		}
		public Object executeUpdate(String sql,String oprType,String[] columns,Object...paramsObjs){
			Connection conn = this.getConnection();
			PreparedStatement pra=null;
			ResultSet rs = null;
			
				try {
					if("insert".equalsIgnoreCase(oprType)){
						pra=conn.prepareStatement(sql,columns);
					}else{
						pra=conn.prepareStatement(sql);
					}
					//2.1、设置占位符的值
					if(paramsObjs!=null && paramsObjs.length>0){
						for(int i=0;i<paramsObjs.length;i++){
							pra.setObject(i+1, paramsObjs[i]);
						}
					}
					//3、执行sql语句
					int rows=pra.executeUpdate();//执行增删改功能并返回受影响的行数
					//4、如果是insert获得主键
					if("insert".equalsIgnoreCase(oprType)){
						rs=pra.getGeneratedKeys();//获得产生的键
						int primaryKey=0;
						if(rs.next()){
							primaryKey=rs.getInt(1);
						}
						//1、如果是insert：返回类型是Integer[]
						return new Integer[]{rows,primaryKey};
					}else{
						return new Integer(rows);//2、如果是update和delete：返回类型是Integer
					}
					
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException(e.getMessage());
				} finally{
					this.closeAll(rs, pra, conn);
				}
			
		}
		
	}
	
	


